﻿using System.Collections.Generic;
using Extented.UI.Core.Utils;
using System.Windows.Media;

namespace System.Windows
{
    public static class PointExtension
    {
        /// <summary>
        /// 返回System.Windows.Point与另一个System.Windows.Point的中点
        /// </summary>
        /// <param name="point"></param>
        /// <param name="otherPoint"></param>
        /// <returns></returns>
        public static Point MiddlePoint(this Point point, Point otherPoint)
        {
            return new Point((point.X + otherPoint.X) / 2, (point.Y + otherPoint.Y) / 2);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="startPoint"></param>
        /// <param name="endPoint"></param>
        /// <param name="radius"></param>
        /// <returns></returns>
        public static Point RadialEdgePoint(this Point startPoint, Point endPoint, double radius)
        {
            MathLine vectorLine = new MathLine(startPoint, endPoint);
            double t = radius / Math.Sqrt(vectorLine.A * vectorLine.A + vectorLine.B * vectorLine.B);
            if (t.IsNotNumber()) return startPoint;
            double dx = Math.Abs(vectorLine.B) * t * Math.Sign(endPoint.X - startPoint.X);
            double dy = Math.Abs(vectorLine.A) * t * Math.Sign(endPoint.Y - startPoint.Y);
            return new Point(startPoint.X + dx, startPoint.Y + dy);
        }

        /// <summary>
        /// 返回点在直线上的投影点
        /// </summary>
        /// <param name="point"></param>
        /// <param name="line"></param>
        /// <returns></returns>
        public static Point MirrorPoint(this Point point, MathLine line)
        {
            MathLine perpendicular = line.Perpendicular(point);
            Point? middle = line.Intersect(perpendicular);
            if (!middle.HasValue) return point;
            double dx = ((Point)middle).X - point.X;
            double dy = ((Point)middle).Y - point.Y;
            return new Point(point.X + 2 * dx, point.Y + 2 * dy);
        }

        /// <summary>
        /// 获取距离某点最近的矩形
        /// </summary>
        /// <param name="point">点</param>
        /// <param name="rects">矩形集合</param>
        /// <returns></returns>
        public static Rect GetNearestRect(this Point point, IEnumerable<Rect> rects)
        {
            return point.GetNearestRect(rects, (p, r) => ((Vector)p - (Vector)r.Center()).Length);
        }

        /// <summary>
        /// 获取距离某点最近的矩形
        /// </summary>
        /// <param name="point">点</param>
        /// <param name="rects">矩形集合</param>
        /// <param name="measure">执行方法</param>
        /// <returns></returns>
        public static Rect GetNearestRect(this Point point, IEnumerable<Rect> rects, Func<Point, Rect, double> measure)
        {
            Rect nearestRect = new Rect();
            double distance = double.MaxValue;
            foreach (Rect rect in rects)
            {
                double currentDistance = measure(point, rect);
                if (currentDistance < distance)
                {
                    nearestRect = rect;
                    distance = currentDistance;
                }
            }
            return nearestRect;
        }

        /// <summary>
        /// 求两点间的距离
        /// </summary>
        /// <param name="point">第一个点</param>
        /// <param name="otherPoint">第二个点</param>
        /// <returns></returns>
        public static double Distance(this Point point, Point otherPoint)
        {
            return ((Vector)point - (Vector)otherPoint).Length;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="pt"></param>
        /// <param name="from"></param>
        /// <returns></returns>
        public static Point ToRootVisualSafe(this Point pt, object from)
        {
            try
            {
                return ToRootVisual(pt, from);
            }
            catch
            {
                return pt;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="pt"></param>
        /// <param name="from"></param>
        /// <returns></returns>
        public static Point ToRootVisual(this Point pt, object from)
        {
            UIElement fromElement = from as UIElement;
            if (fromElement == null) return pt;
            GeneralTransform gt = fromElement.TransformToVisual(GetRootVisual(fromElement));
            return gt.Transform(pt);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="pt"></param>
        /// <param name="from"></param>
        /// <returns></returns>
        public static Point ToLocalSafe(this Point pt, object from)
        {
            try
            {
                return ToLocal(pt, from);
            }
            catch
            {
                return pt;
            }
        }

        /// <summary>
        /// 转换一个System.Windows.Point
        /// </summary>
        /// <param name="pt"></param>
        /// <param name="from"></param>
        /// <returns></returns>
        public static Point ToLocal(this Point pt, object from)
        {
            UIElement fromElement = from as UIElement;
            if (fromElement == null) return pt;
            GeneralTransform gt = GetRootVisual(fromElement).TransformToVisual(fromElement);
            return gt.Transform(pt);
        }

        #region

        /// <summary>
        /// 
        /// </summary>
        /// <param name="d"></param>
        /// <returns></returns>
        private static FrameworkElement GetRootVisual(DependencyObject d)
        {
            FrameworkElement topElement = d as FrameworkElement;
            while (d != null)
            {
                d = VisualTreeHelper.GetParent(d);
                if (d is FrameworkElement)
                    topElement = d as FrameworkElement;
            }
            return topElement;
        }
        #endregion
    }
}